<?php

namespace Portal\Api;

use Portal\Common\DataApi as Api;
// use PhalApi\Api;
use Portal\Domain\Menu as MenuDomain;
use PhalApi\Exception\BadRequestException;

/**
 * 菜单接口
 * @author chenwengen 20240420
 */
class Menus extends Api
{
    // public $typeArr = ['1' => 'MENU','2' => 'CATALOG','3' => 'EXTLINK','4' => 'BUTTON'];

    public function getRules()
    {
        return array(
           'menus' => array(
                'keywords' => array('name' => 'keywords', 'type' => 'string', 'require' => false,'desc' => '',),
                'status' =>  array('name' => 'status', 'type' => 'enum', 'require' => false,'range' => array('0', '1'),'desc' => '状态'),
            ),
            // 'deleteData' => array(
            //     'ids' => array('name' => 'id', 'type' => 'array', 'format' => 'explode', 'seperator' => ',', 'require' => true, 'desc' => \PhalApi\T('ids to delete'))
            // ),
            'deleteDataIDs' => array(
                'ids' => array('name' => 'ids', 'type' => 'array', 'format' => 'explode', 'seperator' => ',', 'require' => true, 'desc' => \PhalApi\T('ids to delete'))
            ),
             'createData' => array(
                'parent_id' => array('name' => 'parentId', 'type' => 'int',  'require' => true, 'min' => 0, 'desc' => '父id'),
                'name' => array('name' => 'name', 'type' => 'string',  'require' => false, 'len' => 64,'desc' => '菜单名称'),
                'route_name' => array('name' => 'routeName', 'type' => 'string',  'require' => false, 'len' => 64,'desc' => '菜单名称'),
                'type' =>  array('name' => 'type', 'type' => 'enum', 'require' => true,'range' => array(1, 2,3,4),'desc' => '菜单类型（1-菜单 2-目录 3-外链 4-按钮）'),
                'route_path' => array('name' => 'routePath','type' => 'string','require' => false,'desc' => '路由路径','len' => 128),
                'component' => array('name' => 'component','type' => 'string','require' => false,'len' => 128, 'desc' => '组件路径',),
                'perm' => array('name' => 'perm','type' => 'string','require' => false,'len' => 128, 'desc' => '权限标识',),
                'visible' => array('name' => 'visible', 'type' => 'enum', 'default' => 1,'require' => false,'range' => array('0', '1'),'desc' => '显示状态(1-显示;0-隐藏)'),
                'sort' => array('name' => 'sort','type' => 'int','require' => false,'default' => 0,'min' => 0,'desc' => '排序'),
                'icon' => array('name' => 'icon','type' => 'string','requrie' => false,'len' => 64, 'desc' => '菜单图标',),
                'redirect' => array('name' => 'redirect','type' => 'string','require' => false,'len' => 128,'desc' => '跳转地址'),
                'always_show' => array('name' => 'alwaysShow', 'type' => 'enum', 'require' => false,'default' => 0,'range' => array('0','1'),'desc' => '【目录只有一个子路由是否始终显示(1:是 0:否)'),
                'keep_alive' => array('name' => 'keepAlive','type' => 'enum', 'require' => false,'default' => 0,'range' => array('0','1'),'desc' => '【菜单】是否开启页面缓存(1:是 0:否)'),
                'params' => array('name' => 'params', 'type' => 'array', 'format' => 'json', 'require' => false,'desc' => '路由参数 JSON格式的数组参数'),
           ),
            'updateData' => array(
                'id' => array('name' => 'id', 'type' => 'int', 'require' => true, 'min' => 1, 'desc' => 'ID'),
                'parent_id' => array('name' => 'parentId', 'type' => 'int',  'require' => true, 'min' => 0, 'desc' => '父id'),
                'name' => array('name' => 'name', 'type' => 'string',  'require' => false, 'len' => 64,'desc' => '菜单名称'),
                'type' =>  array('name' => 'type', 'type' => 'enum', 'require' => true,'range' => array('1', '2','3','4'),'desc' => '菜单类型（1-菜单 2-目录 3-外链 4-按钮）'),
                'route_path' => array('name' => 'routePath','type' => 'string','require' => false,'desc' => '路由路径',),
                'route_name' => array('name' => 'routeName','type' => 'string','require' => false,'desc' => '路由名称',),
                'component' => array('name' => 'component','type' => 'string','require' => false,'len' => 128, 'desc' => '组件路径',),
                'perm' => array('name' => 'perm','type' => 'string','require' => false,'desc' => '权限标识',),
                'visible' => array('name' => 'visible', 'type' => 'enum', 'require' => false,'range' => array('0', '1'),'desc' => '显示状态(1-显示;0-隐藏)'),
                'sort' => array('name' => 'sort','type' => 'int','require' => false,'min' => 0,'desc' => '排序'),
                'icon' => array('name' => 'icon','type' => 'string','requrie' => false,'len' => 64, 'desc' => '菜单图标',),
                'redirect' => array('name' => 'redirect','type' => 'string','require' => false,'len' => 128,'desc' => '跳转地址'),
                'always_show' => array('name' => 'alwaysShow', 'type' => 'enum', 'require' => false,'range' => array('0','1'),'desc' => '【目录只有一个子路由是否始终显示(1:是 0:否)'),
                'keep_alive' => array('name' => 'keepAlive','type' => 'enum', 'require' => false,'range' => array('0','1'),'desc' => '【菜单】是否开启页面缓存(1:是 0:否)'),
                 'params' => array('name' => 'params', 'type' => 'array', 'format' => 'json', 'require' => false,'desc' => '路由参数 JSON格式的数组参数'),
            ),
              'getData' => array(
                'id' => array('name' => 'id', 'type' => 'int', 'require' => true, 'min' => 1, 'desc' => 'ID'),
            ),
             "options" => array(
                "onlyParent" => array('name' => 'onlyParent', 'type' => 'enum', 'require' => false,'range' => array(true,false),'desc' => '是否只查询父级菜单'),
            ),
            'visible' => array(
                'id' => array('name' => 'id', 'type' => 'int', 'require' => true, 'min' => 1, 'desc' => 'ID'),
                "visible" => array('name' => 'visible', 'type' => 'enum', 'require' => true,'range' => array(1,0),'desc' => '显示状态(1:显示;0:隐藏)'),
            ),

      );

    }
    protected function getDataModel()
    {
        return new \Portal\Model\Menu();
    }
    /**
         * 修改菜单显示状态
         * @desc 修改菜单显示状态
         */
    public function visible()
    {
        $this->getDataModel()::notorm()->where(['id' => $this->id])->update(['visible' => $this->visible]);
        return true;
    }
    /**
     * 菜单下拉列表
     * @desc 菜单下拉列表
     */
    public function options()
    {
        $this->permissionRequired(["sys:menu:query"]);
        $menuDomain = new MenuDomain();
        $returnData = $menuDomain->getOptions($this->onlyParent);
        return $returnData;
    }
    /**
     * 路由列表
     * @desc 路由列表
     */
    public function routes()
    {

        $menuDomain = new MenuDomain();
        $returnData = $menuDomain->routes();
        return $returnData;
    }

    /**
    *菜单列表
    * @desc 菜单列表
    * @return array    data   列表数据
    */
    public function menus()
    {
        $this->permissionRequired(["sys:menu:query"]);
        $where = [];
        if ($this->keywords !== null && trim($this->keywords) != '') {
            $where['name LIKE ?'] = array("%$this->keywords%");
        }
        if ($this->status !== null) {
            $where['visible'] = $this->status;
        }
        $menusDomain = new MenuDomain();
        $returnData = $menusDomain->menus($where);
        if (!$returnData) {
            $returnData = [];
        }
        return $returnData;
    }

    // 列表返回的字段
    protected function getTableListSelect()
    {
        return '*';
    }

    // 列表的默认排序
    protected function getTableListOrder()
    {
        return 'id DESC';
    }

    // 查询条件
    protected function getTableListWhere($where)
    {
        return $where;
    }

    // 取到列表数据后的加工处理
    protected function afterTableList($items)
    {
        return $items;
    }
    /**
      * 新增菜单
      * @desc 新增菜单
      * @return int id 新纪录的ID
      */
    public function createData()
    {
        $this->permissionRequired(["sys:menu:add"]);
        $model = $this->getDataModel();

        // $newData = $this->newData;
        $array_keys = array_keys($this->getApiRules());
        $newData = [];
        foreach ($array_keys as $key) {
            if ($this->$key !== null) {
                $newData[$key] = $this->$key;
            }
        }
        // 检测必传字段
        foreach ($this->createDataRequireKeys() as $key) {
            if (!isset($newData[$key]) || $newData[$key] === '') {
                throw new BadRequestException(\PhalApi\T('{name} require, but miss', array('name' => $key)));
            }
        }
        // 排除字段
        foreach ($this->createDataExcludeKeys() as $key) {
            unset($newData[$key]);
        }
        //验证提交数据有效性
        $this->validate($newData);
        //验证提交数据有效性

        // 更多初始化的字段数据
        $newData = $this->beforeCreateData($newData);

        if (empty($newData)) {
            throw new BadRequestException(\PhalApi\T('miss post data'));
        }

        $id = 0;
        try {
            $id = $model->insert($newData);
        } catch (\PDOException $ex) {
            throw new BadRequestException(\PhalApi\DI()->debug ? $ex->getMessage() : \PhalApi\T('system error, please contact engeneer'));
        }

        return $this->returnDataResult(array('id' => intval($id)));
    }

    // 必须提供的字段
    protected function createDataRequireKeys()
    {
        return array('parent_id','name','type');
    }

    // 不允许客户端写入的字段
    protected function createDataExcludeKeys()
    {
        return array('id','create_time','update_time');
    }

    // 创建时更多初始化的数据
    protected function beforeCreateData($newData)
    {

        //
        $time = time();
        $newData['create_time'] = $time;
        $newData['update_time'] = $time;
        if (!$newData['route_path']) {
            $newData['route_path'] = '';
        }
        if ($newData['parent_id'] == 0) {
            $newData['tree_path'] = '0';
            if (!filter_var($newData['redirect'], FILTER_VALIDATE_URL)) {
                $newData['component'] = 'Layout';
            }
        } else {
            //获取树等级
            $menuDomain = new MenuDomain();
            $treePath = $menuDomain->getTreePath($newData['parent_id']);
            $newData['tree_path'] = implode(',', $treePath);
        }
        if ($newData['params']) {
            $newparams = [];
            foreach ($newData['params'] as $param) {
                $newparams[$param['key']] = $param['value'];
            }
            $newData['params'] = json_encode($newparams, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        } else {
            $newData['params'] = null;
        }
        return $newData;
    }
    // public function demo()
    // {
    //     $menuDomain=new MenuDomain();
    //     $childrenArr=$menuDomain->getChildren(20);
    //     echo json_encode($childrenArr);
    //     exit();
    // }
    /**
     * 根据ID删除数据
     * @desc 根据单个ID删除数据，也可以调整成根据自定义的条件删除数据
     */
    public function deleteData()
    {
        // $model = $this->getDataModel();

        // if (is_array($this->ids) && !empty($this->ids)) {
        //     $menuDomain = new MenuDomain();
        //     //判断要删除的id是否有子级，所有子级一起删除
        //     foreach ($this->ids as $id) {
        //         $this->ids = array_merge($this->ids, $menuDomain->getChildren($id));
        //     }
        // }
        // $rows = $this->ids ? $model->deleteIds($this->ids) : 0;
        // $this->deleteRoleMenu();
        // return $this->returnDataResult(array('deleted_num' => $rows));
        $id = $this->id;
        $this->ids = [$id];
        $this->deleteDataIDs();
    }

    // 删除数据的条件加工
    protected function getDeleteDataWhere($where)
    {
        return $where;
    }

    /**
     * 批量删除
     * @desc 通用数据接口，根据ID批量删除数据
     */
    public function deleteDataIDs()
    {
        $this->permissionRequired(["sys:menu:delete"]);
        if (empty($this->ids)) {
            throw new BadRequestException('请指定要删除的菜单', 1);

        }
        # # 查询要删除的菜单
        $model = $this->getDataModel();
        # # 检查是否存在子菜单
        $childmenusData = $model::notorm()->select('id')->where(['parent_id' => $this->ids])->fetchAll();
        if ($childmenusData) {
            throw new BadRequestException('存在子菜单，无法删除', 1);
        }
        $rows = $this->ids ? $model->deleteIds($this->ids) : 0;
        return $this->returnDataResult(array('deleted_num' => $rows));
    }

    /**
     * 菜单表单数据
     * @desc 菜单表单数据
     * @return object
     * @exception 403 菜单信息不存在
     */
    public function getData()
    {
        $this->permissionRequired(["sys:menu:edit"]);
        $where = array('id' => $this->id);
        $whereParams = array();
        $select = $this->getDataSelect();

        // 前置条件加工
        $where = $this->getGetDataWhere($where);

        $model = $this->getDataModel();
        $data = $model->getData($where, $whereParams, $select);
        if (!$data) {
            throw new BadRequestException("菜单信息不存在", 3);
        }
        $data = $this->afterGetData($data);
        return $this->returnDataResult($data);
    }

    // 获取单个数据时需要返回的字段
    protected function getDataSelect()
    {
        return 'id,parent_id AS parentId,name,type,route_name AS routeName,route_path AS routePath,component,perm,visible,sort,icon,redirect,keep_alive AS keepAlive,always_show AS alwaysShow,params';
    }

    // 前置条件加工
    protected function getGetDataWhere($where)
    {
        return $where;
    }

    // 取到数据后的加工处理
    protected function afterGetData($data)
    {
        if (isset($data['id'])) {
            $data['id'] = strval($data['id']);
        }
        if (isset($data['parentId'])) {
            $data['parentId'] = strval($data['parentId']);
        }
        if (isset($data['params']) && $data['params']) {
            $params = json_decode($data['params'], true);
            $newParams = [];
            foreach ($params as $param => $val) {
                $newParam["key"] = $param;
                $newParam["value"] = $val;
                $newParams[] = $newParam;
            }
            $data['params'] = $newParams;
        }
        return $data;
    }
    /**
    * 更新数据
    * @desc 通用数据接口，根据ID更新单条数据
    * @return int|boolean updated_num 更新的数据条数，0表示无更新，1表示更新成功
    */
    public function updateData()
    {
        $this->permissionRequired(["sys:menu:edit"]);
        $model = $this->getDataModel();
        // $updateData = $this->data;
        $array_keys = array_keys($this->getApiRules());
        $updateData = [];
        foreach ($array_keys as $key) {
            if ($this->$key !== null && $key !== 'data') {
                $updateData[$key] = $this->$key;
            }
        }
        //验证提交数据有效性
        $this->validate($updateData);

        //验证提交数据有效性
        unset($updateData['id']);
        foreach ($this->updateDataRequireKeys() as $key) {
            if (!isset($updateData[$key]) || $updateData[$key] === '') {
                throw new BadRequestException(\PhalApi\T('{name} require, but miss', array('name' => $key)));
            }
        }

        foreach ($this->updateDataExcludeKeys() as $key) {
            unset($updateData[$key]);
        }

        if (empty($updateData)) {
            throw new BadRequestException(\PhalApi\T('miss update data'));
        }

        $updateData = $this->beforeUpdateData($updateData);

        try {
            $where = array('id' => $this->id);
            $where = $this->getUpdateDataWhere($where);

            $rows = $model->updateAll($where, $updateData);

            return $this->returnDataResult(array('updated_num' => $rows));
        } catch (\PDOException $ex) {
            throw new BadRequestException(\PhalApi\DI()->debug ? $ex->getMessage() : \PhalApi\T('system error, please contact engeneer'));
        }
    }

    // 更新时必须提供的字段
    protected function updateDataRequireKeys()
    {
        return array();
    }

    // 更新时不允许更新的字段
    protected function updateDataExcludeKeys()
    {
        return array('id','create_time','update_time','tree_path');
    }

    // 获取更新数据的条件
    protected function getUpdateDataWhere($where)
    {
        return $where;
    }

    // 在更新数据前的处理
    protected function beforeUpdateData($updateData)
    {
        $time = time();
        $updateData['update_time'] = $time;
        // $typeArr = array_flip($this->typeArr);
        //类型转换
        // if (isset($typeArr[$updateData['type']])) {
        //     $updateData['type'] = $typeArr[$updateData['type']];
        // } else {
        //     $updateData['type'] = null;
        // }
        //判断是否有修改过顶级id
        $getParentData = \Portal\Model\Menu::notorm()->select('parent_id')->where(['id' => $this->id])->fetchOne();
        if (isset($getParentData['parent_id']) && intval($getParentData['parent_id']) != $updateData['parent_id']) {


            //有修改过父级菜单，重新获取等级树
            if ($updateData['parent_id'] == 0) {
                $updateData['tree_path'] = '0';
                if (!filter_var($updateData['redirect'], FILTER_VALIDATE_URL)) {
                    $updateData['component'] = 'Layout';
                }
            } else {
                //查询要修改的父级菜单是否存在
                $checkParentData = $this->getDataModel()::notorm()->select('id')->where(['id' => $updateData['parent_id']])->fetchOne();
                if (!$checkParentData) {
                    throw new BadRequestException("父菜单不存在", 3);

                }
                //查询要修改的父级菜单是否存在
                //获取树等级
                $menuDomain = new MenuDomain();
                $treePath = $menuDomain->getTreePath($updateData['parent_id']);
                $updateData['tree_path'] = implode(',', $treePath);
            }
        }

        if ($updateData['params']) {
            $newparams = [];
            foreach ($updateData['params'] as $param) {
                $newparams[$param['key']] = $param['value'];
            }
            $updateData['params'] = json_encode($newparams, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        } else {
            $updateData['params'] = null;
        }
        return $updateData;
    }

    private function validate($data)
    {
        # 根据菜单类型进行特定验证
        //菜单类型
        $type = $data['type'];
        switch ($type) {
            case "1":
                # 菜单类型需要routeName, routePath, component
                if (!isset($data['route_name']) || trim($data['route_name']) == '') {
                    throw new BadRequestException("菜单类型必须设置路由名称");
                }
                #验证routeName唯一性
                if (isset($data['id'])) {
                    //修改去除当前id
                    $where['id <> ?'] = intval($data['id']);
                }
                $where['route_name'] = $data['route_name'];
                $checkData = $this->getDataModel()::notorm()->select('id')->where($where)->fetchOne();
                if ($checkData) {
                    throw new BadRequestException("路由名称已存在");
                }
                #菜单类型必须设置路由路径
                if (!isset($data['route_path']) || trim($data['route_path']) == '') {
                    throw new BadRequestException("菜单类型必须设置路由路径");
                }
                #菜单类型必须设置组件路径
                if (!isset($data['component']) || trim($data['component']) == '') {
                    throw new BadRequestException("菜单类型必须设置组件路径");
                }
                break;
            case "2":
                # 目录
                # 目录需要routePath
                if (!isset($data['route_path']) || trim($data['route_path']) == '') {
                    throw new BadRequestException("目录类型必须设置路由路径");
                }
                break;
            case "3":
                # 外链需要routePath，且以http或https开头
                if (!isset($data['route_path']) || trim($data['route_path']) == '') {
                    throw new BadRequestException("外链类型必须设置URL地址");
                }
                #判断是否是url
                if (filter_var($data['route_path'], FILTER_VALIDATE_URL) == false) {
                    throw new BadRequestException("外链类型必须设置URL地址外链地址必须以http://或https://开头");
                }
                break;
            case "4":
                # 按钮需要权限标识perm
                if (!isset($data['perm']) || trim($data['perm']) == '') {
                    throw new BadRequestException("按钮类型必须设置权限标识");
                }
                break;
        }

    }
}
